#include <stdio.h>

#include "driver/gpio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

#define OUTPUT_PIN_A 2  // GPIO2
#define OUTPUT_PIN_B 4  // GPIO4

#define INPUT_PIN_A 14 // GPIO14
#define INPUT_PIN_B 12 // GPIO12

#define ESP_INTR_FLAG_DEFAULT 0

bool input_trigger = false;
uint16_t input_gpio_num = 0;

static void IRAM_ATTR gpio_isr_handler(void* arg)
{
    input_trigger = true;
    input_gpio_num = (uint32_t) arg;
}

bool input_pin_b_state = false;

void app_main(void)
{
    printf("GPIO DEMO\n");

    // Configure output pins

    gpio_config_t io_conf_output;
    io_conf_output.intr_type = GPIO_INTR_DISABLE;
    io_conf_output.mode = GPIO_MODE_OUTPUT;
    io_conf_output.pin_bit_mask = (1ULL << OUTPUT_PIN_A) | (1ULL << OUTPUT_PIN_B);
    io_conf_output.pull_down_en = 0;
    io_conf_output.pull_up_en = 0;
    gpio_config(&io_conf_output);
    gpio_set_level(OUTPUT_PIN_A, 1);
    gpio_set_level(OUTPUT_PIN_B, 0);

    // Configure input pin

    gpio_config_t io_conf_input;
    io_conf_input.intr_type = GPIO_INTR_POSEDGE;
    io_conf_input.mode = GPIO_MODE_INPUT;
    io_conf_input.pin_bit_mask = (1ULL << INPUT_PIN_A) | (1ULL << INPUT_PIN_B);
    io_conf_input.pull_down_en = 0;
    io_conf_input.pull_up_en = 1;

    // Configure input pin A interrupt

    gpio_config(&io_conf_input);
    gpio_set_intr_type(INPUT_PIN_A, GPIO_INTR_POSEDGE);
    gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);
    gpio_isr_handler_add(INPUT_PIN_A, gpio_isr_handler, (void*) INPUT_PIN_A);

    // Input pin B for polling

    input_pin_b_state = gpio_get_level(INPUT_PIN_B);

    uint32_t i = 0;

    while (1) {
        gpio_set_level(OUTPUT_PIN_A, i % 2);
        gpio_set_level(OUTPUT_PIN_B, (i + 1) % 2);
        i++;
        vTaskDelay(10 / portTICK_PERIOD_MS);

        if (input_trigger) {
            input_trigger = false;
            printf("Input GPIO: %d   %d\n", input_gpio_num, gpio_get_level(input_gpio_num));
        }

        if(input_pin_b_state != gpio_get_level(INPUT_PIN_B)) {
            input_pin_b_state = gpio_get_level(INPUT_PIN_B);
            printf("Input GPIO B changed: %d\n", input_pin_b_state);
        }

    }
}
